package org.study.aop.core;

import org.study.aop.bean.AopBeanDefinition;

import org.study.aop.utils.ClassUtils;
import org.study.ioc.bean.BeanDefinition;
import org.study.ioc.bean.PropertyArg;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public class XmlAopApplicationContext extends AopBeanFactoryImpl {
    private String fileName;

    //通过构造函数，直接传入AOP的配置文件
    public XmlAopApplicationContext(String fileName) {
        this.fileName = fileName;
    }

    //初始化，也就是解析aop的配置文件的过程
    public void init() {
        loadFile();
    }

    public void loadFile() {
        List<AopBeanDefinition> aopBeanDefinitions = getAopBeanDefinition();
        if (aopBeanDefinitions != null && !aopBeanDefinitions.isEmpty()) {
            for (AopBeanDefinition beanDefinition :aopBeanDefinitions) {
                Class<?> clz = ClassUtils.loadClass(beanDefinition.getClassName());
                //只是做一个标记
                if(clz == ProxyFactoryBean.class){
                    //注册到aop对应的容器
                    registerBean(beanDefinition.getName(),beanDefinition);
                }else{
                    //注册到ioc容器中
                    regist(beanDefinition.getName(),(BeanDefinition) beanDefinition);
                }

            }
        }
    }

    public List<AopBeanDefinition> getAopBeanDefinition() {
        try {
            //加载文件
            InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
            //构建一个document的工厂
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            //通过工厂生成documentBuilder对象
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            //通过builder,加载文档
            Document document = documentBuilder.parse(inputStream);
            //获取第一个节点也就是根节点
            Element root = document.getDocumentElement();
            ArrayList<AopBeanDefinition> beanDefinitionList = new ArrayList<AopBeanDefinition>();
            //获取根节点的所有子节点,获取的就是<bean>标签
            NodeList nodes = root.getChildNodes();
            //遍历第一层的bean,
            // todo 这里其实可以使用递归或者其他方式来优化，这种是最原始的，比较糙
            for (int i = 0; i < nodes.getLength(); i++) {
                //获取到每一个bean
                Node node = nodes.item(i);
                //如果节点是文档元素
                if (node instanceof Element) {
                    //转换
                    Element ele = (Element) node;
                    //获取节点的id属性
                    String id = ele.getAttribute("id");
                    //获取文档节点的class属性
                    String clszz = ele.getAttribute("class");
                    //获取target属性
                    String target = ele.getAttribute("target");
                    //创建一个Aop的描述数据结构
                    AopBeanDefinition aopBeanDefinition = new AopBeanDefinition();
                    aopBeanDefinition.setName(id);
                    aopBeanDefinition.setClassName(clszz);
                    //不是空和null,需要把属性也解析进来
                    if (target != null && !"".equals(target)) {
                        aopBeanDefinition.setTarget(target);
                    }
                    NodeList propertyNodes = ele.getElementsByTagName("property");
                    //PropertyArg 是ioc容器的模块的一个对象
                    ArrayList<PropertyArg> propertyArgs = new ArrayList();
                    ArrayList<String> interceptorNames = new ArrayList<String>();
                    //遍历下一级节点
                    for (int j = 0; j < propertyNodes.getLength(); j++) {
                        Node nodeTemp = propertyNodes.item(j);
                        //如果是Element对象
                        if (nodeTemp instanceof Element) {
                            PropertyArg propertyArg = new PropertyArg();

                            Element propertyElement = (Element) nodeTemp;
                            //获取节点的下一层节点
                            NodeList childNodes = nodeTemp.getChildNodes();
                            //如果没有下一层节点
                            if (childNodes == null) {
                                String name = propertyElement.getAttribute("name");
                                propertyArg.setName(name);
                                String value = propertyElement.getAttribute("value");
                                if (value != null && !"".equals(value)) {
                                    propertyArg.setValue(value);
                                }
                                String ref = propertyElement.getAttribute("ref");
                                if (ref != null && !"".equals(ref)) {
                                    propertyArg.setRef(ref);
                                }
                                propertyArgs.add(propertyArg);
                            }
                            for (int k = 0; k < childNodes.getLength(); k++) {
                                Node listNode = childNodes.item(k);
                                if (listNode instanceof Element) {
                                    NodeList listChild = listNode.getChildNodes();
                                    if (listChild != null) {
                                        for (int m = 0; m < listChild.getLength(); m++) {
                                            Node interceptorNameNode = childNodes.item(m);
                                            if (interceptorNameNode instanceof Element) {
                                                Element interceptorNameElement = (Element) interceptorNameNode;
                                                String interceptorName = interceptorNameElement.getAttribute("bean");
                                                interceptorNames.add(interceptorName);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    aopBeanDefinition.setPropertyArgs(propertyArgs);
                    aopBeanDefinition.setInterceptorNames(interceptorNames);
                    beanDefinitionList.add(aopBeanDefinition);
                }

            }
            return beanDefinitionList;
        } catch (Exception e) {
            System.out.printf("解析失败" + e.getStackTrace());
        }
        return null;
    }
}
